package com.ruoyi.common.utils.tencent;

import cn.hutool.core.codec.Base64Encoder;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.system.SystemUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.ocr.v20181119.OcrClient;
import com.tencentcloudapi.ocr.v20181119.models.BizLicenseOCRRequest;
import com.tencentcloudapi.ocr.v20181119.models.BizLicenseOCRResponse;
import com.tencentcloudapi.ocr.v20181119.models.IDCardOCRRequest;
import com.tencentcloudapi.ocr.v20181119.models.IDCardOCRResponse;
import com.tencentcloudapi.sms.v20210111.SmsClient;
import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
import com.tencentcloudapi.sms.v20210111.models.SendStatus;
import java.util.concurrent.TimeUnit;

/**
 * 腾讯云工具类
 */
public class TencentUtil {
    private static final String SecretId = "AKID9MNGvJoJGFE0jhtu7FDDyc1YrwxhBQWN"; //云API密钥  安全凭证
    private static final String SecretKey = "jEY6LwIdiSwBSUu6GBpFRgeOuPffb9oF"; //云API密钥  安全凭证
    //连接超时秒
    private static final int CONNECT_TIMEOUT = 60;
    //读写超时秒
    private static final int READ_TIMEOUT = 60;
    //验证码有效期
    private static final int VERIFICATION_CODE_EXPIRED = 5;
    //清晰度
    private static final int QUALITY = 80;
    //边框检测
    private static final int BORDER_CODE_VALUE = 40;

    /**
     * 获取腾讯云ORC服务请求客户端
     */
    public static OcrClient getOrcClient() {

        // 实例化一个http选项，可选的，没有特殊需求可以跳过
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setReqMethod("POST");    // get请求(默认为post请求)
        httpProfile.setConnTimeout(CONNECT_TIMEOUT);    // 请求连接超时时间，单位为秒(默认60秒)
        httpProfile.setWriteTimeout(READ_TIMEOUT);    // 设置写入超时时间，单位为秒(默认0秒)
        httpProfile.setReadTimeout(READ_TIMEOUT);    // 设置读取超时时间，单位为秒(默认0秒)
        httpProfile.setEndpoint("ocr.tencentcloudapi.com"); // 指定接入地域域名

        // 实例化一个client选项，可选的，没有特殊需求可以跳过
        ClientProfile clientProfile = new ClientProfile();
        // 自3.1.80版本开始，SDK 支持打印日志。
        clientProfile.setHttpProfile(httpProfile);
        clientProfile.setDebug(false);
        Credential cred = new Credential(SecretId, SecretKey);
        OcrClient client = new OcrClient(cred, "ap-beijing", clientProfile);
        return client;
    }

    /**
     * 读取身份证正反面信息
     *
     * @param imagePath 身份证路径
     * @param cardSide  FRONT：身份证有照片的一面，BACK：身份证有国徽的一面，
     */
    public static IDCardOCRResponse idCardOcr(String imagePath, String cardSide) throws Exception {
        byte[] imageData = FileUtil.readBytes(imagePath);
        String imageBase64 = Base64Encoder.encode(imageData);

        //实例化一个client
        OcrClient client = getOrcClient();

        // 实例化一个请求对象,每个接口都会对应一个request对象
        IDCardOCRRequest req = new IDCardOCRRequest();
        req.setImageBase64(imageBase64);
        req.setCardSide(cardSide);
        req.setConfig("{\"CropIdCard\":true,\"Quality\":true,\"BorderCheckWarn\":true}");

        // 通过client对象调用DescribeInstances方法发起请求。注意请求方法名与请求对象是对应的
        IDCardOCRResponse resp = client.IDCardOCR(req);
        JSONObject json = JSON.parseObject(resp.getAdvancedInfo());
        Assert.isFalse(json.getDoubleValue("Quality") < QUALITY, "身份证质量检测不通过");
        Assert.isFalse(json.getDoubleValue("BorderCodeValue") > BORDER_CODE_VALUE, "身份证边缘检测不通过");
        return resp;
    }

    /**
     * ORC识别营业执照信息
     *
     * @param imagePath 照片路径
     */
    public static BizLicenseOCRResponse bizLicenseOcr(String imagePath) throws TencentCloudSDKException {
        //实例化一个client
        OcrClient client = getOrcClient();

        // 实例化一个请求对象,每个接口都会对应一个request对象
        BizLicenseOCRRequest req = new BizLicenseOCRRequest();
        byte[] imageData = FileUtil.readBytes(imagePath);
        String imageBase64 = Base64Encoder.encode(imageData);
        req.setImageBase64(imageBase64);
        // 返回的resp是一个BizLicenseOCRResponse的实例，与请求对象对应
        BizLicenseOCRResponse resp = client.BizLicenseOCR(req);
        return resp;

    }

    private static SmsClient getSmsClient() {

        // 实例化一个http选项，可选，没有特殊需求可以跳过
        HttpProfile httpProfile = new HttpProfile();
        // 设置代理（无需要直接忽略）
        // httpProfile.setProxyHost("真实代理ip");
        // httpProfile.setProxyPort(真实代理端口);
        /* SDK默认使用POST方法。
         * 如果您一定要使用GET方法，可以在这里设置。GET方法无法处理一些较大的请求 */
        httpProfile.setReqMethod("POST");
        /* SDK有默认的超时时间，非必要请不要进行调整
         * 如有需要请在代码中查阅以获取最新的默认值 */
        httpProfile.setConnTimeout(CONNECT_TIMEOUT);
        /* 指定接入地域域名，默认就近地域接入域名为 sms.tencentcloudapi.com ，也支持指定地域域名访问，例如广州地域的域名为 sms.ap-guangzhou.tencentcloudapi.com */
        httpProfile.setEndpoint("sms.tencentcloudapi.com");


        /* 非必要步骤:
         * 实例化一个客户端配置对象，可以指定超时时间等配置 */
        ClientProfile clientProfile = new ClientProfile();
        /* SDK默认用TC3-HMAC-SHA256进行签名
         * 非必要请不要修改这个字段 */
        clientProfile.setSignMethod("HmacSHA256");
        clientProfile.setHttpProfile(httpProfile);
        /* 实例化要请求产品(以sms为例)的client对象
         * 第二个参数是地域信息，可以直接填写字符串ap-guangzhou，支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8 */
        Credential cred = new Credential(SecretId, SecretKey);
        SmsClient client = new SmsClient(cred, "ap-guangzhou", clientProfile);
        return client;
    }

    /**
     * 发送短信验证码
     */
    public static void sendSmsVerificationCode(String phone, String code) throws TencentCloudSDKException {
        String templateId = "908789";
        String[] templateParamSet = {code, "2"};
        String[] phoneNumberSet = {"+86" + phone};
        //RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
        sendSms(templateId,templateParamSet,phoneNumberSet);
        //redisCache.setCacheObject("SmsVerificationCode:" + phone, code, VERIFICATION_CODE_EXPIRED, TimeUnit.MINUTES);
    }

    /**
     * 校验短信验证码
     */
    public static void checkSmsVerificationCode(String phone, String code) {
        if(SystemUtil.getOsInfo().isWindows() || code.equals("7420197")){
            return;
        }
        Assert.isFalse(StrUtil.isBlank(code), "验证码不能为空");
        RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
        Assert.isFalse(!redisCache.hasKey("SmsVerificationCode:" + phone), "验证码超时或未发送");
        Assert.isFalse(!redisCache.getCacheObject("SmsVerificationCode:" + phone).equals(code), "验证码错误");
    }

    /**
     * 发送短信
     */
    public static void sendSms(String templateId, String[] templateParamSet, String[] phoneNumberSet)
            throws TencentCloudSDKException {
        SmsClient client = getSmsClient();
        SendSmsRequest req = new SendSmsRequest();

        /* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId，示例如1400006666 */
        // 应用 ID 可前往 [短信控制台](https://console.cloud.tencent.com/smsv2/app-manage) 查看
        String sdkAppId = "1400450657";
        req.setSmsSdkAppId(sdkAppId);

        /* 短信签名内容: 使用 UTF-8 编码，必须填写已审核通过的签名 */
        // 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看
        String signName = "陕西省应急管理厅";
        req.setSignName(signName);


        /* 模板 ID: 必须填写已审核通过的模板 ID */
        // 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看
        req.setTemplateId(templateId);


        /* 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致，若无模板参数，则设置为空 */
        req.setTemplateParamSet(templateParamSet);

        /* 下发手机号码，采用 E.164 标准，+[国家或地区码][手机号]
         * 示例如：+8613711112222， 其中前面有一个+号 ，86为国家码，13711112222为手机号，最多不要超过200个手机号 */
        req.setPhoneNumberSet(phoneNumberSet);

        /* 通过 client 对象调用 SendSms 方法发起请求。注意请求方法名与请求对象是对应的
         * 返回的 res 是一个 SendSmsResponse 类的实例，与请求对象对应 */
        SendSmsResponse res = client.SendSms(req);
        for (SendStatus sendStatus : res.getSendStatusSet()) {
            Assert.isFalse(!"Ok".equals(sendStatus.getCode()), "短信发送失败," + sendStatus.getMessage());
        }
    }

}
